package com.szwistar.common.datastruct;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * HEX 文件处理
 */
public class HexFile {
	public static final String HEX_EOF = ":00000001FF";
	private List<HexFileData> datas = new ArrayList<HexFileData>();

	/**
	 * 从hex文件读取数据
	 * @param file
	 * @throws IOException
	 * @throws Exception
	 */
	public void fromFile(File file) throws IOException {
		BufferedReader br = new BufferedReader(new FileReader(file));
		try {
			String line = null;
			HexFileData hexFileData = null;
			int baseAddr = 0x0;
			datas.clear();
			while( (line=br.readLine())!=null ) {
				//hex文件结束
				if( line.equalsIgnoreCase(HEX_EOF) ) {
					break;
				}

				//第一个字符是冒号，后面才是数据开始
				line = line.trim().substring(1);

				byte[] context = new byte[line.length()/2];
				for( int i=0; i<line.length()/2; i++ ) {
					context[i] = (byte) Short.parseShort(line.substring(i*2, i*2+2), 16);
				}
				int dataLen = context[0] & 0xFF;
				int addr = (context[1]<<8 & 0xFF00) | (context[2] & 0xFF);
				byte dataType = context[3];

				//DataRecord数据的地址要加上基地址
				if( dataType == HexFileData.TYPE_DR ) {
					addr = baseAddr | addr;
				}
				if( hexFileData!=null
					&& dataType==hexFileData.getDataType()
					&& addr==hexFileData.getNextAddr() ) {
					hexFileData.appendData(context, 4, dataLen);
				}
				else {
					hexFileData = new HexFileData();
					hexFileData.setAddr(addr);
					hexFileData.setDataType(dataType);
					hexFileData.setData(context, 4, dataLen);
					datas.add(hexFileData);
					//数据类型为扩展线性地址，表示后面的数据有基地址
					if( dataType == HexFileData.TYPE_ELAR ) {
						baseAddr = Utils.bytesToShort(hexFileData.getData(), 0);
						baseAddr = baseAddr << 16;
					}
					else if( dataType != HexFileData.TYPE_DR ) {
						baseAddr = 0;
					}
				}
			}
		}
		catch(IOException e){
			throw new IOException();
		} finally {
			br.close();
		}
	}

	public void fromFile(String filePath) throws IOException {
		fromFile(new File(filePath));
	}

	/**
	 * 将数据保存到hex文件
	 * @param file
	 * @param lineBytes 每行保存几个字节
	 * @throws IOException
	 */
	public void save2File(File file, int lineBytes) throws IOException {
		if( !file.exists() ) {
			file.createNewFile();
		}
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file));
		for( HexFileData hexFileData : datas ) {
			byte[] data = hexFileData.getData();
			for( int i=0; i<data.length; i+=lineBytes ) {
				int len = Integer.min(data.length-i, lineBytes);
				int addr = hexFileData.getAddr()+i;
				int sum = (len&0xFF) + (addr&0xFF) + ((addr>>8)&0xFF) + hexFileData.getDataType();
				for(int k=i; k<i+len; k++ ) {
					sum += data[k];
				}
				sum = 0x100 - sum&0xFF;
				StringBuffer line = new StringBuffer(":");
				line.append(Utils.byteToHexString((byte) (len&0xFF)));
				line.append(Utils.byteToHexString((byte) ((addr>>8)&0xFF)));
				line.append(Utils.byteToHexString((byte) (addr&0xFF)));
				line.append(Utils.byteToHexString(hexFileData.getDataType()));
				line.append(Utils.bytesToHexString(data, i, len));
				line.append(Utils.byteToHexString((byte) (sum&0xFF)));
				line.append("\r\n");
				osw.write(line.toString());
			}
		}
		osw.write(HEX_EOF);
		osw.flush();
		osw.close();
	}

	public void save2File(String filePath, int lineBytes) throws IOException {
		save2File(new File(filePath), lineBytes);
	}

	public void save2File(String filePath) throws IOException {
		save2File(new File(filePath), 16);
	}

	/**
	 * 修改一段数据
	 * @param addr
	 * @param dataType
	 * @param data
	 */
	public boolean modify(int addr, byte dataType, byte[] data) {
		for( HexFileData hexData : datas ) {
			if( (dataType == hexData.getDataType())
				&& (addr >= hexData.getAddr())
				&& ((addr+data.length) <= hexData.getNextAddr()) ) {
				byte[] dstData = hexData.getData();
				System.arraycopy(data, 0, dstData, addr-hexData.getAddr(), data.length);
				return true;
			}
		}
		return false;
	}

	/**
	 * 获取一段数据
	 * @param addr
	 * @param dataType
	 * @param len
	 * @return
	 */
	public byte[] getData(int addr, byte dataType, int len) {
		for( HexFileData hexData : datas ) {
			if( (dataType == hexData.getDataType())
				&& (addr >= hexData.getAddr())
				&& ((addr+len) <= hexData.getNextAddr()) ) {
				byte[] srcData = hexData.getData();
				byte[] dstData = new byte[len];
				System.arraycopy(srcData, addr-hexData.getAddr(), dstData, 0, len);
				return dstData;
			}
		}
		return null;
	}

	public HexFileData[] getHexDatas() {
		return datas.toArray(new HexFileData[0]);
	}

	/**
	 * 得到该数据包的总的长度
	 * */
	public int getTotalsDataLength() {
		int sum = 0;
		for(int i = 0;i < datas.size(); i++) {
			sum = datas.get(i).getData().length+sum;
		}
		return sum;
	}

	public static void main(String[] args) {
		//HexFile hexFile = new HexFile();
		//HexFile.fromFile(new File("C:/Users/Administrator/Documents/Tencent Files/657735138/FileRecv/RFSwitch-2x.hex"));
		//HexFile.save2File(new File("d:/my.hex"));
		//getDeviceTypeFromHex("FFF0");
		//short ff= (short) 0x4540;
		//System.out.println(ff);
	}
}
